<?php

Raise::load('core.RaiseCollection');

/**
 * TestCoreRaiseCollection class
 * Testing unit of 'phpraise/core/RaiseCollection.php'
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.UnitTest.Test
 */
class TestCoreRaiseCollection extends RaiseTest {
    public static function testClass(){
        self::assertClassExists('RaiseCollection');
        self::assertClassExtends('RaiseCollection', 'RaiseDataType');
        self::assertClassImplements('RaiseCollection', 'ArrayAccess');
        self::assertClassImplements('RaiseCollection', 'Traversable');
        self::assertClassImplements('RaiseCollection', 'IteratorAggregate');
    }

    public static function testAdding(){
        $collection = new RaiseCollection();
        $collection->add(100);
        $collection->add(50);
        $collection->add(62.5);

        self::assertStrictEqual($collection->get(0), 100);
        self::assertStrictEqual($collection->get(1), 50);
        self::assertStrictEqual($collection->get(2), 62.5);
    }

    public static function testRandom(){
        $collection = new RaiseCollection();
        $collection->add(100);
        $collection->add(50);
        $collection->add(62.5);

        $kvp = $collection->random();
        self::assertTrue($collection->keyExists($kvp->key()));
        
        $kvp = $collection->random();
        self::assertTrue($collection->valueExists($kvp->value()));
    }

    public static function testAddingWithKeys(){
        $collection = new RaiseCollection();
        $collection->add('pear', 100);
        $collection->add('orange', 50);
        $collection->add('apple', 62.5);

        self::assertStrictEqual($collection->get('pear'), 100);
        self::assertStrictEqual($collection->get('orange'), 50);
        self::assertStrictEqual($collection->get('apple'), 62.5);
    }

    public static function testAddingWithRaiseKeyValuePair(){
        $collection = new RaiseCollection();
        $collection->add(new RaiseKeyValuePair('pear', 100));
        $collection->add(new RaiseKeyValuePair('orange', 50));
        $collection->add(new RaiseKeyValuePair('apple', 62.5));

        self::assertStrictEqual($collection->get('pear'), 100);
        self::assertStrictEqual($collection->get('orange'), 50);
        self::assertStrictEqual($collection->get('apple'), 62.5);
    }

    public static function testRemove(){
        $collection = new RaiseCollection();
        $collection->add('pear', 100);
        $collection->add('orange', 50);
        $collection->add('apple', 62.5);
        
        self::assertStrictEqual($collection->count(), 3);

        $collection->remove('pear');
        self::assertStrictEqual($collection->count(), 2);
        self::assertStrictEqual($collection->last(), 62.5);
        self::assertStrictEqual($collection->first(), 50);

        $collection->remove('apple');
        self::assertStrictEqual($collection->count(), 1);
        self::assertStrictEqual($collection->last(), 50);
        self::assertStrictEqual($collection->first(), 50);
    }

    public static function testMethods(){
        $collection = new RaiseCollection();
        $collection->add('orange', 100);
        $collection->add(50);
        $collection->add(62.5);

        self::assertTrue($collection->keyExists('orange'));
        self::assertTrue($collection->valueExists(50));
        self::assertFalse($collection->keyExists('pear'));
        self::assertFalse($collection->valueExists(20.56));

        self::assertStrictEqual($collection->count(), 3);
        self::assertStrictEqual($collection->last(), 62.5);
        self::assertStrictEqual($collection->first(), 100);

        $collection->clear();
        self::assertStrictEqual($collection->count(), 0);
        self::assertStrictEqual($collection->last(), null);
        self::assertStrictEqual($collection->first(), null);

        self::assertObjectClass($collection->iterator(), 'RaiseIterator');
    }
    
    public static function testIndexOf(){
        $collection = new RaiseCollection();
        $collection->add(100);
        $collection->add(50);
        $collection->add(62.5);
        $collection->add(20);
        $collection->add(55.8);
        $collection->add(10);
        $collection->add(62.5);

        self::assertType($collection->indexesOf(62.5), 'object');
        self::assertObjectClass($collection->indexesOf(62.5), 'RaiseCollection');
        self::assertStrictEqual($collection->indexesOf(62.5)->count(), 2);
        self::assertTrue($collection->indexesOf(62.5)->valueExists(2));
        self::assertTrue($collection->indexesOf(62.5)->valueExists(6));
        self::assertStrictEqual($collection->indexesOf(100)->count(), 1);
        self::assertStrictEqual($collection->indexesOf(20)->count(), 1);

        self::assertStrictEqual($collection->indexOf(100), 0);
        self::assertStrictEqual($collection->indexOf(62.5), 2);
        self::assertStrictEqual($collection->indexOf(10), 5);
    }

    public static function testPrepend(){
        $collectionA = new RaiseCollection();
        $collectionA->add(100);
        $collectionA->add(50);
        $collectionA->add(62.8);
        self::assertStrictEqual($collectionA->count(), 3);

        $collectionB = new RaiseCollection();
        $collectionB->add(55.8);
        $collectionB->add(10);
        $collectionB->add(62.5);
        self::assertStrictEqual($collectionB->count(), 3);

        $collectionA->prepend($collectionB);
        self::assertStrictEqual($collectionA->count(), 6);

        self::assertStrictEqual($collectionA->first(), 55.8);
        self::assertStrictEqual($collectionA->last(), 62.8);

        self::assertStrictEqual($collectionA->get(3), 100);
        self::assertStrictEqual($collectionA->get(1), 10);
    }

    public static function testAppend(){
        $collectionA = new RaiseCollection();
        $collectionA->add(100);
        $collectionA->add(50);
        $collectionA->add(62.8);
        self::assertStrictEqual($collectionA->count(), 3);

        $collectionB = new RaiseCollection();
        $collectionB->add(55.8);
        $collectionB->add(10);
        $collectionB->add(62.5);
        self::assertStrictEqual($collectionB->count(), 3);

        $collectionA->append($collectionB);
        self::assertStrictEqual($collectionA->count(), 6);

        self::assertStrictEqual($collectionA->first(), 100);
        self::assertStrictEqual($collectionA->last(), 62.5);

        self::assertStrictEqual($collectionA->get(3), 55.8);
        self::assertStrictEqual($collectionA->get(1), 50);
    }

    public static function testReverse(){
        $collection = new RaiseCollection();
        $collection->add(100);
        $collection->add(50);
        $collection->add(62.5);

        self::assertStrictEqual($collection->first(), 100);
        self::assertStrictEqual($collection->last(), 62.5);
        $collection->reverse();
        self::assertStrictEqual($collection->first(), 62.5);
        self::assertStrictEqual($collection->last(), 100);
    }

    public static function testIsAssociativeSequential(){
        $collection = new RaiseCollection();
        $collection->add(100);
        $collection->add(50);
        $collection->add(62.5);
        self::assertTrue($collection->isSequential());
        self::assertFalse($collection->isAssociative());

        $collection->add('test','23012');
        $collection->add('tes2t','012');
        $collection->add(452);
        self::assertFalse($collection->isSequential());
        self::assertTrue($collection->isAssociative());

        $collection = new RaiseCollection();
        $collection->add(0, 34034);
        $collection->add(1, 34124);
        $collection->add(2, 343.4);
        self::assertTrue($collection->isSequential());
        self::assertFalse($collection->isAssociative());
    }

    public static function testJoin(){
        $collection = new RaiseCollection(20, 50, 100);
        self::assertStrictEqual($collection->join(), '2050100');
        self::assertStrictEqual($collection->join(';'), '20;50;100');
    }

    public static function testSorting(){
        $c = new MockComparator();
        $c->column('a');

        $testArray = array(
            array('a' => 5),
            array('a' => 2),
            array('a' => 3),
            array('a' => 8),
            array('a' => 1)
        );

        $resultArray = array(
            array('a' => 1),
            array('a' => 2),
            array('a' => 3),
            array('a' => 5),
            array('a' => 8)
        );

        $resultArray2 = array(
            array('a' => 1),
            array('a' => 2),
            array('a' => 3),
            array('a' => 5),
            array('a' => 6),
            array('a' => 8)
        );


        $collection = new RaiseCollection($testArray);
        $collection->sort($c);
        self::assertEqual($collection->toArray(), $resultArray);
        $collection->add(array('a' => 6));
        $collection->sort($c);
        self::assertEqual($collection->toArray(), $resultArray2);
        
        try{
            $collection->sort(null);
            self::addError('Sorting failed to throw exception when passed with non-IRaiseComparator');
        }catch(Exception $ex){
            self::assertTrue(true);
        }

    }
}